
module jade.tpl.js.Buffer ;

import jade.tpl.Template ;

static DBuffer_Constructor	buffer_constructor  ;
static DBuffer_Prototype	buffer_prototype ;

final class DBuffer_Constructor : Dfunction {

	final this() {
		super(0, Dfunction_prototype);
	}
	

	final  override void* Construct(CallContext *cc, Value *ret, Value[] args)
	{
		int len = 1024;
		int step = 1024 ;
		if( args.length > 0 && args[0].isNumber ) {
			len	= cast(int) args[0].toInteger ;
			if( len < 512 || len > 102400 ) {
				len	=  1024 ;
			}
			if( args.length > 1 && args[1].isNumber ) {
				step	= cast(int) args[1].toInteger ;
				if( step < 512 || step > 102400 ) {
					step	=  1024 ;
				}
			}
		}
		
		DBuffer_Object obj	= new DBuffer_Object( buffer_prototype ) ;
		obj.bu	= new vBuffer(len, step);
		ret.putVobject(obj);
		return null;
	}
	
	final override void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] args){

		return null;
	}
	
}


final class DBuffer_Prototype : Dobject {

	final this(Dobject prototype){
		super(prototype);
		
		static enum NativeFunctionData nfd[] =
		[
		    {"clear", &Buffer_rototype_clear, 0} ,
		    {"length", &Buffer_rototype_length, 0} ,
		    {"slice", &Buffer_rototype_slice, 3} ,
		    {"strip", &Buffer_rototype_strip, 0} ,
		    {"unstrip", &Buffer_rototype_unstrip, 0} ,
		    {"toString", &Buffer_rototype_toString, 0} ,
		];

		DnativeFunction.init(this, nfd, DontDelete | ReadOnly );
	}
	
	static void* Buffer_rototype_clear(Dobject pthis, CallContext* cc, Dobject othis, Value* ret, Value[] argv) {
		static const func_name = "buffer.clear";
		ErrInfo errinfo;
		DBuffer_Object _this	= cast(DBuffer_Object) othis ;
		if( _this is null ) {
                	return RuntimeError(&errinfo, ERR_TYPE_ERROR , func_name);
		}
		_this.bu.clear  ;
		
		ret.putVobject(othis);
		return null ;
	}
	
	static void* Buffer_rototype_slice(Dobject pthis, CallContext* cc, Dobject othis, Value* ret, Value[] args) {
		static const func_name = "buffer.slice";
		ErrInfo errinfo;
		DBuffer_Object _this	= cast(DBuffer_Object) othis ;
		if( _this is null ) {
                	return RuntimeError(&errinfo, ERR_TYPE_ERROR , func_name);
		}
		int i , j ;
		string bu = cast(string) _this.bu.slice ;
		j	= bu.length ;
		if( args.length > 0 && args[0].isNumber ){
			int k	= args[0].toInt32 ;
			if( k>=0 && k <= bu.length ){
				i	= k ;
			}
		}
		if( args.length > 1 && args[1].isNumber ){
			int k	= args[1].toInt32 ;
			if( k>=i && k <= bu.length ){
				j	= k ;
			}
		}
		if( args.length > 2 ) {
			ret.putVstring( bu[i..j].idup );
		} else {
			ret.putVstring( bu[i..j]);
		}
		return null ;
	}
	
	static void* Buffer_rototype_length(Dobject pthis, CallContext* cc, Dobject othis, Value* ret, Value[] argv) {
		static const func_name = "buffer.length";
		ErrInfo errinfo;
		DBuffer_Object _this	= cast(DBuffer_Object) othis ;
		if( _this is null ) {
                	return RuntimeError(&errinfo, ERR_TYPE_ERROR , func_name);
		}
		ret.putVnumber( _this.bu.length ) ;
		return null ;
	}
	
	static void* Buffer_rototype_strip(Dobject pthis, CallContext* cc, Dobject othis, Value* ret, Value[] args) {
		static const func_name = "buffer.strip";
		ErrInfo errinfo;
		DBuffer_Object _this	= cast(DBuffer_Object) othis ;
		if( _this is null ) {
                	return RuntimeError(&errinfo, ERR_TYPE_ERROR , func_name);
		}
		if( args.length ){
			foreach(ref v ;args ){
				switch( v.vtype ){
					case V_NUMBER:
					case V_BOOLEAN:
						_this.bu( v.toString );
						break;
					case V_NULL:
						_this.bu(TEXT_null);
						break;
					case V_UNDEFINED:
						_this.bu(TEXT_undefined);
						break;
					case V_STRING:
					default:
						_this.bu.strip(v.toString);
				}
			}
		}
		ret.putVobject(othis);
		return null ;
	}
	
	static void* Buffer_rototype_unstrip(Dobject pthis, CallContext* cc, Dobject othis, Value* ret, Value[] args) {
		static const func_name = "buffer.unstrip";
		ErrInfo errinfo;
		DBuffer_Object _this	= cast(DBuffer_Object) othis ;
		if( _this is null ) {
                	return RuntimeError(&errinfo, ERR_TYPE_ERROR , func_name);
		}
		if( args.length ){
			foreach(ref v ;args ){
				switch( v.vtype ){
					case V_NUMBER:
					case V_BOOLEAN:
						_this.bu( v.toString );
						break;
					case V_NULL:
						_this.bu(TEXT_null);
						break;
					case V_UNDEFINED:
						_this.bu(TEXT_undefined);
						break;
					case V_STRING:
					default:
						_this.bu.unstrip(v.toString);
				}
			}
		}
		ret.putVobject(othis);
		return null ;
	}
	
	static void* Buffer_rototype_toString(Dobject pthis, CallContext* cc, Dobject othis, Value* ret, Value[] args) {
		static const func_name = "buffer.toString";
		ErrInfo errinfo;
		DBuffer_Object _this	= cast(DBuffer_Object) othis ;
		if( _this is null ) {
                	return RuntimeError(&errinfo, ERR_TYPE_ERROR , func_name);
		}
		
		
		string _ret	= cast(string) _this.bu.slice  ;
		if( args.length > 0 ) {
			ret.putVstring( _ret.idup );
		} else {
			ret.putVstring( _ret );
		}
		return null ;
	}
}

final class DBuffer_Object : Dobject {
	
	package vBuffer bu ;
	
	final this(Dobject prototype){
		super(prototype);
	}
	
	static void Init(Dobject obj){
		if( buffer_constructor !is null ) {
			return ;
		}
		buffer_constructor	= new DBuffer_Constructor ;
		buffer_prototype	= new DBuffer_Prototype(Dobject_prototype) ;
		
      		buffer_constructor.Put(TEXT_prototype, buffer_prototype, DontEnum | DontDelete | ReadOnly);
		obj.Put("Buffer", buffer_constructor, DontEnum | DontDelete | ReadOnly);
	}
	

	final override void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] args){
		
		if( args.length is 0 ) {
			ret.putVstring( cast(string) bu.slice );
			return null ;
		}
		
		foreach(ref v ;args ){
			switch( v.vtype ){
				case V_STRING:
				case V_NUMBER:
				case V_BOOLEAN:
					bu( v.toString);
					break;
				case V_NULL:
					bu(TEXT_null);
					break;
				case V_UNDEFINED:
					bu(TEXT_undefined);
					break;
				default:
					bu( v.toString);
			}
		}
		
		ret.putVobject(this);
		return null;
	}
}

